using System;
using System.Collections.Generic;
using System.Linq;
using TeamCityMonitor.Models;
using TeamCityMonitor.Repository;
using TeamCityMonitor.Repository.Caches;
using TeamCitySharp.DomainEntities;

namespace TeamCityMonitor.Manager.CustomCreators
{
    public class StatisticsCreator : ICustomModelCreator
    {
        private readonly ITeamCityRepository _teamCityRepository;

        public StatisticsCreator(ITeamCityRepository teamCityRepository)
        {
            _teamCityRepository = teamCityRepository;
        }

        public bool IsActive()
        {
            return Properties.Settings.Default.ShowStatistics;
        }

        public List<CustomModel> GetCustomModels()
        {
            var customModels = new List<CustomModel>();

            customModels.Add(GetNoOfStatusBuildsSince());

            customModels.Add(GetTopNoOfBuildsByUser());

            customModels.Add(GetTopNoOfSuccessfullBuildConfigs());
            customModels.Add(GetTopNoOfFailingBuildConfigs());
            customModels.Add(GetTopNoOfErrorBuildConfigs());

            customModels.Add(GetOverview());

            customModels.ForEach(model => model.ImageUrl = GetRandomStatisticsPicture());

            return customModels;
        }

        private CustomModel GetOverview()
        {
            var numberOfProjects = _teamCityRepository.GetNoOfProjects();
            var numberOfConfigurations = _teamCityRepository.GetNoOfConfigurations();

            var overview = string.Format("There are {0} projects configured on the server.\r\nWith a stunning number of {1} associated configurations.", numberOfProjects,numberOfConfigurations);
            return new CustomModel
            {
                Title = string.Format("Overview"),
                Footer = overview
            };
        }

        private CustomModel GetTopNoOfSuccessfullBuildConfigs()
        {
            var configs = _teamCityRepository.GetBuildConfigurations().ToList();

            var mostSuccessFullConfigs = new List<ConfigStat>();

            configs.ForEach(config => mostSuccessFullConfigs.Add(
                                                                        new ConfigStat 
                                                                            {
                                                                                BuildConfig = config,
                                                                                BuildCount = _teamCityRepository.GetNoOfSuccessfullBuildsByBuildConfig(config)
                                                                            }));
            mostSuccessFullConfigs = mostSuccessFullConfigs.OrderByDescending(item => item.BuildCount).ToList();

            var topList = "";
            mostSuccessFullConfigs.Take(Properties.Settings.Default.NoOfTopBuildConfigs)
                .ToList().ForEach(entry => topList = string.Format("{0}{1} successfull builds in '{2}, {3}'\r\n", topList, entry.BuildCount, entry.BuildConfig.ProjectName, entry.BuildConfig.Name));

            return new CustomModel
            {
                Title = string.Format("Top {0} build configurations by number of successfull builds", Properties.Settings.Default.NoOfTopBuildConfigs),
                Footer = topList
            };
        }

        private CustomModel GetTopNoOfFailingBuildConfigs()
        {
            var configs = _teamCityRepository.GetBuildConfigurations().ToList(); ;

            var mostFailingConfigs = new List<ConfigStat>();
            configs.ForEach(config => mostFailingConfigs.Add(
                                                                        new ConfigStat
                                                                        {
                                                                            BuildConfig = config,
                                                                            BuildCount = _teamCityRepository.GetNoOfFailingBuildsByBuildConfig(config)
                                                                        }));
            mostFailingConfigs = mostFailingConfigs.OrderByDescending(item => item.BuildCount).ToList();
            var topList = "";
            mostFailingConfigs.Take(Properties.Settings.Default.NoOfTopBuildConfigs)
                .ToList().ForEach(entry => topList = string.Format("{0}{1} failing builds in '{2}, {3}'\r\n", topList, entry.BuildCount, entry.BuildConfig.ProjectName, entry.BuildConfig.Name));

            return new CustomModel
            {
                Title = string.Format("Top {0} build configurations by number of failing builds", Properties.Settings.Default.NoOfTopBuildConfigs),
                Footer = topList
            };
        }

        private CustomModel GetTopNoOfErrorBuildConfigs()
        {
            var configs = _teamCityRepository.GetBuildConfigurations().ToList(); 

            var mostErrorConfigs = new List<ConfigStat>();
            configs.ForEach(config => mostErrorConfigs.Add(
                                                                        new ConfigStat
                                                                        {
                                                                            BuildConfig = config,
                                                                            BuildCount = _teamCityRepository.GetNoOfErrorBuildsByBuildConfig(config)
                                                                        }));
            mostErrorConfigs = mostErrorConfigs.OrderByDescending(item => item.BuildCount).ToList();

            var topList = "";
            mostErrorConfigs.Take(Properties.Settings.Default.NoOfTopBuildConfigs)
                .ToList().ForEach(entry => topList = string.Format("{0}{1} error builds in '{2}, {3}'\r\n", topList, entry.BuildCount, entry.BuildConfig.ProjectName, entry.BuildConfig.Name));

            return new CustomModel
                       {
                           Title = string.Format("Top {0} build configurations by number of error related builds", Properties.Settings.Default.NoOfTopBuildConfigs),
                           Footer = topList
                       };
        }

        private CustomModel GetTopNoOfBuildsByUser()
        {
            var users = _teamCityRepository.GetUsers().ToList();

            var sortedList = new List<UserStat>();
            users.ForEach(user => sortedList.Add( new UserStat { User = user, BuildCount = _teamCityRepository.GetNoOfBuildsByUser(user) }));
            sortedList = sortedList.OrderByDescending(item => item.BuildCount).ToList();

            var noOfBuildsByUserString = GenerateNoOfBuildsPrUserString(sortedList);

            return new CustomModel
            {
                Title = string.Format("Top {0} number of builds by user", Properties.Settings.Default.NoOfUserToDisplayStatisticsFor),
                Footer = noOfBuildsByUserString
            };
        }

        private string GenerateNoOfBuildsPrUserString(List<UserStat> sortedList)
        {
            var retval = "";

            var userStats = sortedList.Take(Properties.Settings.Default.NoOfUserToDisplayStatisticsFor);

            userStats.ToList().ForEach(userStat => retval = string.Format("{0}{1} builds by {2}\r\n", retval, userStat.BuildCount, ( userStat.User.Name ?? userStat.User.Username)));

            return retval;
        }

        private CustomModel GetNoOfStatusBuildsSince()
        {
            var successfullBuilds = _teamCityRepository.GetNoOfSuccessfullBuilds();
            var failingBuilds = _teamCityRepository.GetNoOfFailingBuilds();
            var errorBuilds = _teamCityRepository.GetNoOfErrorBuilds();

            return new CustomModel
                       {
                           Title = string.Format("Build statistics from the last {0} days", Properties.Settings.Default.DaysBackToPerformStatistisc),
                           Footer = string.Format("{0}\r\n{1}\r\n{2}",
                                string.Format("Number of successfull builds: {0}", successfullBuilds),
                                string.Format("Number of failing builds: {0}", failingBuilds),
                                string.Format("Number of error builds: {0}",  errorBuilds)),
                       };
        }

        private string GetRandomStatisticsPicture()
        {
            var pictures = new List<string>
                               {
                                   "green_statistics.png",
                                   "blue_statistics.png",
                                   "pink_statistics.png",
                                   "screen-statistics.png",
                                   "graphs-statistics.png",
                                   "block_statistics.png",
                                   "piechart_statistics1.png",
                                   "piechart-statistics2.png",
                                   "piechart-statistics3.png",
                               };

            var randomNumber = new Random(DateTime.Now.Millisecond).Next(0, pictures.Count - 1);

            return string.Format("../../Content/{0}", pictures[randomNumber]);
        }

        private class UserStat
        {
            public User User { get; set; }
            public int BuildCount { get; set; }
        }

        private class ConfigStat
        {
            public BuildConfig BuildConfig { get; set; }
            public int BuildCount { get; set; }
        }
    }
}